from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
from collections import defaultdict


# 夹治具申购表
class FixtureSubscriptionForm(models.Model):
    _name = 'sb.fixture.subscription'
    _description = 'Fixture Subscription Form'
    _inherit = ['mail.thread', 'mail.activity.mixin']
    _order = "name desc"

    name = fields.Char(string="Name", default="New")
    state = fields.Selection([
        ('new', 'NEW'),
        ('inquiry', 'Inquiry'),
        ('sale_a', 'Sales Approval'),
        ('w_place_o', 'Wait Place Order'),
        ('a_place_o', 'Already Place Order'),
        ('completed', 'Completed'),
        ('cancel', 'Cancel'),
    ], tracking=True, default='new', copy=False)
    apply_uid = fields.Many2one('res.users', string='Apply Uid',
                                default=lambda self: self.env.user.id if not self.env.user._is_public() else False,
                                copy=False)
    fixture_ids = fields.Many2many('product.template', string="Subscription Fixtures",
                                   domain="[('categ_id.code', 'in', ['FXCR','FXET','FXPN'])]")

    sb_fixture_subscription_item_ids = fields.One2many('sb.fixture.subscription.item', 'sb_fixture_subscription_id',
                                                       copy=False)

    # 销售单
    customer_id = fields.Many2one('res.partner', string="Customer", domain="[('id', 'in', t_customer_ids)]")
    sale_order_id = fields.Many2many('sale.order', string="Sale Order", readonly=False,
                                     compute="_compute_sale_order_id", store=True)
    product_tml_id = fields.Many2one('product.template', string="MPN", domain="[('categ_id.code', '=', 'CHP')]")
    # 可选单位范围客户字段
    t_customer_ids = fields.Many2many('res.partner', compute='_compute_t_customer_ids')
    s_product_metre = fields.Float(compute="_compute_s_product_metre", store=True, String="Total Square Meter")
    sale_user_id = fields.Many2one('res.users', compute="_compute_sale_user_id", store=True, string="Sale Uid")
    nre = fields.Monetary(compute="_compute_nre", store=True, string="Total NRE", currency_field='currency_id')
    thai_nre = fields.Monetary(compute="_compute_thai_nre", store=True, string="Thai Total NRE",
                               currency_field='p_currency_id')
    currency_id = fields.Many2one('res.currency', string='Customer Currency', related="customer_id.currency_id")
    p_currency_id = fields.Many2one('res.currency', default=lambda self: self.env.company.currency_id)
    supplier_currency_id = fields.Many2one('res.currency', compute="_compute_supplier_currency_id", store=True,
                                           string="Supplier Currency")

    sb_workflow_id = fields.Many2one('sb.workflow', string="Sale Workflow", copy=False)
    sb_workflow_state = fields.Selection(related="sb_workflow_id.state", readonly=True, string="Approval Status",
                                         store=True)
    sb_workflow_item_ids = fields.One2many(related="sb_workflow_id.sb_workflow_item_ids", string="Approval Items",
                                           copy=False)

    total_s_price_thai = fields.Monetary('Total Sale Price Thai', compute="_compute_total_s_price_thai",
                                         store=True, currency_field='p_currency_id')

    proportion_of_fixture_costs = fields.Float('Proportion Fixture Costs',
                                               compute="_compute_proportion_of_fixture_costs",
                                               store=True, digits=(12, 4))

    # 采购单
    po_ids = fields.Many2many(comodel_name='purchase.order',
                              relation='sb_fixture_purchase_rel',
                              column1='fixture_id',
                              column2='purchase_id',
                              string="Purchase Order", copy=False)
    pr_delivery_date = fields.Date(string="PR Delivery date")
    picking_ids = fields.Many2many(comodel_name='stock.picking',
                                   compute='compute_picking_ids',
                                   string="Picking")
    # expected_arrival_date = fields.Datetime(string="Expected Arrival Date", related="po_id.s_date_planned")

    usd_to_thb_rate = fields.Float(string="USD to THB", compute="_compute_usd_to_thb_rate")

    total_price = fields.Monetary(
        'Untaxed Total', compute='_compute_total_price',
        store=True, tracking=True, currency_field='supplier_currency_id')
    total_price_thai = fields.Monetary(
        'Untaxed Total Thai', compute='_compute_total_price_thai',
        store=True, tracking=True, currency_field='p_currency_id')
    # compute='_compute_total_price_thai',
    remark = fields.Text(string="Remark")

    @api.depends('sale_order_id')
    def _compute_total_s_price_thai(self):
        for item in self:
            total_s_price = 0
            if item.sale_order_id:
                for s_id in item.sale_order_id:
                    total_s_price += float(s_id.amount_total)
            if item.currency_id.name == 'USD':
                item.total_s_price_thai = total_s_price * item.usd_to_thb_rate
            else:
                item.total_s_price_thai = total_s_price

    @api.depends('total_price_thai')
    def _compute_proportion_of_fixture_costs(self):
        for item in self:
            proportion_of_fixture_costs = 0
            if item.total_price_thai and item.total_s_price_thai:
                proportion_of_fixture_costs = item.total_price_thai / item.total_s_price_thai
            item.proportion_of_fixture_costs = proportion_of_fixture_costs

    @api.depends('sb_fixture_subscription_item_ids.price')
    def _compute_total_price(self):
        for cost in self:
            cost.total_price = sum(line.price * line.qty for line in cost.sb_fixture_subscription_item_ids)

    @api.depends('sb_fixture_subscription_item_ids.price', 'usd_to_thb_rate')
    def _compute_total_price_thai(self):
        for cost in self:
            if cost.sb_fixture_subscription_item_ids and cost.usd_to_thb_rate:
                cost.total_price_thai = sum(
                    line.price * line.qty for line in cost.sb_fixture_subscription_item_ids) * cost.usd_to_thb_rate
            else:
                cost.total_price_thai = cost.total_price

    @api.onchange('create_date')
    def _compute_usd_to_thb_rate(self):
        # 获取美元和泰铢的汇率
        usd_currency = self.env.ref('base.USD')  # 获取美元货币记录
        thb_currency = self.env.ref('base.THB')  # 获取泰铢货币记录

        if usd_currency and thb_currency:
            # 使用订单的创建日期作为查询汇率的日期
            for rec in self:
                create_date = rec.create_date
                # usd_to_thb = usd_currency.with_context(date=create_date).rate / thb_currency.with_context(date=create_date).rate
                rec.usd_to_thb_rate = self.env['res.currency']._get_conversion_rate(usd_currency, thb_currency, date=create_date)

    @api.depends('nre')
    def _compute_thai_nre(self):
        for item in self:
            if item.nre and item.currency_id.name == 'USD':
                item.thai_nre = item.nre * item.usd_to_thb_rate
            else:
                item.thai_nre = item.nre

    @api.depends('sb_fixture_subscription_item_ids')
    def _compute_supplier_currency_id(self):
        for record in self:
            supplier_currency_id = self.env.company.currency_id.id

            if record.sb_fixture_subscription_item_ids:
                # 设置 supplier_currency_id 为唯一的币种
                if record.sb_fixture_subscription_item_ids[0].supplier_id.property_purchase_currency_id:
                    supplier_currency_id = record.sb_fixture_subscription_item_ids[
                        0].supplier_id.property_purchase_currency_id.id

            self.supplier_currency_id = supplier_currency_id

    @api.depends('sale_order_id')
    def _compute_nre(self):
        for item in self:
            nre_sum = 0
            if item.sale_order_id:
                for it in item.sale_order_id:
                    nre_sum += it.s_nre
            item.nre = nre_sum

    @api.depends('sale_order_id')
    def _compute_s_product_metre(self):
        for item in self:
            product_metre_sum = 0
            if item.sale_order_id:
                for it in item.sale_order_id:
                    product_metre_sum += it.s_product_metre
            item.s_product_metre = product_metre_sum

    @api.depends('sale_order_id')
    def _compute_sale_user_id(self):
        for item in self:
            if item.sale_order_id:
                item.sale_user_id = item.sale_order_id[0].user_id.id
            else:
                item.sale_user_id = False

    @api.depends('product_tml_id', 'customer_id')
    def _compute_sale_order_id(self):
        for item in self:
            sale_order_ids = []
            if item.product_tml_id and item.customer_id:
                sale_order_ids = item.env['sale.order'].search([('first_line.s_planned_qty', '=', 0),
                                                                ('state', '=', 'sale'),
                                                                ('status', '=', 'active'),
                                                                ('product_id', '=', item.product_tml_id.id),
                                                                ('partner_id', '=', item.customer_id.id)])
            item.sale_order_id = sale_order_ids

    @api.depends('product_tml_id')
    def _compute_t_customer_ids(self):
        for item in self:
            cu_ids = []
            if item.product_tml_id:
                pn_ids = item.env['customer.item.code'].search([('product_id', '=', item.product_tml_id.id),
                                                                ('active', '=', True)])
                if pn_ids:
                    for it in pn_ids:
                        cu_ids.append(it.customer_id.id)
            item.t_customer_ids = cu_ids

    @api.constrains('sb_workflow_state')
    def _check_sb_workflow_state(self):
        for record in self:
            if record.sb_workflow_state == 'approve' and record.state == 'sale_a':
                record.sale_approve()

    def submit_application(self):
        self.ensure_one()
        if not self.fixture_ids:
            raise UserError(
                _('Subscription Fixtures empty'))
        if not self.sale_order_id:
            raise UserError(
                _('Sale Order Null'))
        # if self.s_product_metre < 20:
        #     raise UserError(
        #         _('Total Square Meter < 20'))
        self.state = 'inquiry'
        self.name = self.env['ir.sequence'].next_by_code('sb.fixture.serial')
        for fixture_id in self.fixture_ids:
            self.env['sb.fixture.subscription.item'].create({
                'sb_fixture_subscription_id': self.id,
                'product_tml_id': fixture_id.id
            })

    def confirm_price(self):
        self.ensure_one()

        # 限制选择的供应商币种必须为美元或泰铢，且所有供应商币种必须一致
        if self.sb_fixture_subscription_item_ids:
            base_currency_id = self.sb_fixture_subscription_item_ids[0].supplier_id.property_purchase_currency_id
            if not base_currency_id:
                raise ValidationError(
                    _('Unable to select vendor: Currency information is not configured. Please set the currency in the vendor profile first.'))

            for item in self.sb_fixture_subscription_item_ids:
                if not item.supplier_id.property_purchase_currency_id:
                    raise ValidationError(
                        _('Unable to select vendor: Currency information is not configured. Please set the currency in the vendor profile first.'))

                if item.supplier_id.property_purchase_currency_id.name not in ['USD', 'THB']:
                    raise ValidationError(_('Supplier Currency must be USD or THB.'))

                if item.supplier_id.property_purchase_currency_id != base_currency_id:
                    raise ValidationError(_("All added suppliers must be in the same currency."))

        total_price_thai = sum(
            line.price * line.qty for line in self.sb_fixture_subscription_item_ids) * self.usd_to_thb_rate
        if total_price_thai > self.thai_nre:
            new_wf_id = self.env['sb.workflow'].sudo().create({
                'name': self.name + '- Approval Flow',
                'approval_time': fields.Datetime.now(),
                'workflow_type': 'clamping_f',
                'sb_fixture_subscription_id': self.id
            })
            self.sb_workflow_id = new_wf_id.id
            index = 1
            state = 'approval'
            if self.sale_user_id:
                self.env['sb.workflow.item'].sudo().create({
                    'name': '跟单员审批',
                    'user_group_ids': [self.sale_user_id.id],
                    'sb_workflow_id': new_wf_id.id,
                    'state': 'approval',
                    'audit_level': index
                })
                state = 'wait_forward'
                index += 1
            self.env['sb.workflow.item'].sudo().create({
                'name': '市场上级审批',
                'user_group_ids': [44],
                'sb_workflow_id': new_wf_id.id,
                'state': state,
                'audit_level': index
            })

            self.state = 'sale_a'
        else:
            self.state = 'w_place_o'

    def sale_approve(self):
        self.ensure_one()
        self.state = 'w_place_o'

    def place_order(self):
        """
        创建采购单
        """
        self.ensure_one()
        supplier_default_dict = defaultdict(list)
        for po_line in self.sb_fixture_subscription_item_ids:
            supplierinfo_id = self.env['product.supplierinfo'].search([
                ('product_tmpl_id', '=', po_line.product_tml_id.id),
                ('partner_id', '=', po_line.supplier_id.id)], limit=1)
            if supplierinfo_id:
                supplierinfo_id.write({
                    'price': po_line.price,
                    'currency_id': po_line.currency_id.id,
                })
            else:
                self.env['product.supplierinfo'].create({
                    'partner_id': po_line.supplier_id.id,
                    'product_tmpl_id': po_line.product_tml_id.id,
                    'min_qty': 1,
                    'price': po_line.price,
                })
            if not po_line.product_tml_id.product_variant_id:
                raise ValidationError(_('产品 %s 已归档, 请先解除归档后下单') % po_line.product_tml_id.name)
            supplier_default_dict[po_line.supplier_id].append((0, 0, {
                'product_id': po_line.product_tml_id.product_variant_id.id,
                'fixture_item_id': po_line.id,
                'product_qty': po_line.qty,
                'product_uom': po_line.product_tml_id.uom_po_id.id,
                'price_unit': po_line.price,
                'name': po_line.product_tml_id.display_name,
            }))
        purchase_ids = []
        for supplier_id, line in supplier_default_dict.items():
            if supplier_id.property_purchase_currency_id:
                res = self.sudo().env['purchase.order'].sudo().create({
                    'partner_id': supplier_id.id,
                    'fixture_id': self.id,
                    'picking_type_id': self.env.ref('stock.picking_type_in').id,
                    'order_line': line,
                    'origin': self.name,
                    'currency_id': supplier_id.property_purchase_currency_id.id,
                    'payment_term_id': supplier_id.property_supplier_payment_term_id.id
                })
            else:
                res = self.sudo().env['purchase.order'].sudo().create({
                    'partner_id': supplier_id.id,
                    'fixture_id': self.id,
                    'picking_type_id': self.env.ref('stock.picking_type_in').id,
                    'order_line': line,
                    'origin': self.name,
                    'payment_term_id': supplier_id.property_supplier_payment_term_id.id
                })
            purchase_ids.append(res.id)
        self.po_ids = [(6, 0, purchase_ids)]
        self.state = 'a_place_o'
        return self.action_view_purchase()

    def action_view_purchase(self):
        purchase_ids = self.po_ids.ids
        if len(purchase_ids) == 1:
            # 如果只有一张采购单，返回表单视图
            return {
                'type': 'ir.actions.act_window',
                'name': 'Purchase Order',
                'res_model': 'purchase.order',
                'view_mode': 'form',
                'res_id': purchase_ids[0],
                'target': 'current',
            }
        else:
            return {
                'type': 'ir.actions.act_window',
                'name': 'Purchase Orders',
                'res_model': 'purchase.order',
                'view_mode': 'tree,form',
                'domain': [('id', 'in', purchase_ids)],
                'target': 'current',
            }

    @api.depends('po_ids')
    def compute_picking_ids(self):
        for record in self:
            record.picking_ids = record.po_ids.mapped('picking_ids')

    def action_view_picking(self):
        if len(self.picking_ids) == 1:
            # 如果只有一张采购单，返回表单视图
            return {
                'type': 'ir.actions.act_window',
                'name': _('Picking Order'),
                'res_model': 'stock.picking',
                'view_mode': 'form',
                'res_id': self.picking_ids[0].id,
                'target': 'current',
            }
        else:
            return {
                'type': 'ir.actions.act_window',
                'name': _('Picking Orders'),
                'res_model': 'stock.picking',
                'view_mode': 'tree,form',
                'domain': [('id', 'in', self.picking_ids.ids)],
                'target': 'current',
            }


class FixtureSubscriptionFormItem(models.Model):
    _name = 'sb.fixture.subscription.item'
    _description = 'Fixture Subscription Item'

    sb_fixture_subscription_id = fields.Many2one('sb.fixture.subscription')
    product_tml_id = fields.Many2one('product.template', string="MPN")
    qty = fields.Integer('Quantity', default=1)
    supplier_id = fields.Many2one('res.partner', string="Supplier",
                                  domain=[('supplier_rank', '=', 1), ('is_company', '=', True), ('name', '!=', False)])
    currency_id = fields.Many2one('res.currency', string='Currency',
                                  related="supplier_id.property_purchase_currency_id")
    price = fields.Float(string="Price")
